using System;
using System.ComponentModel;
using System.Threading;
using GeneralDFS.BusinessLogical.Nodes;

namespace GeneralDFS.BusinessLogical.RemoteObject
{
    public partial class NameNodeRemoteObject
    {
        // toggled on join/first-run of ReJoin to provide some buffer between join and consistency check
        private bool m_HasReJoinRun = false;    

        /// <summary>
        /// Maintenance task to perform ring consistency checking and re-joining to keep a Chord
        /// ring stable under extreme churn and in cases of ring damage.
        /// </summary>
        /// <param name="sender">The calling backgroundworker.</param>
        /// <param name="ea">Args (ignored for this task).</param>
        private void ReJoin(object sender, DoWorkEventArgs ea)
        {
            var me = (BackgroundWorker)sender;

            while (!me.CancellationPending)
            {
                try
                {
                    // if this is the first iteration, then the core logic
                    // is skipped, as the first iteration generally occurs
                    // right after node Join - allowing a short buffer for
                    // routing structures to stabilize improves the utility
                    // of the ReJoin facility.
                    if (this.m_HasReJoinRun)
                    {
                        // first find the successor for the seed node
                        if (this._seedNode != null)
                        {
                            var seedSuccessor = FindSuccessor(this._seedNode.ID);

                            // if the successor is not equal to the seed node, something is fishy
                            if (seedSuccessor.ID != this._seedNode.ID)
                            {
                                // if the seed node is still active, re-join the ring to the seed node
                                var instance = NameNode.GetInstance(this._seedNode);
                                if (instance!=null)
                                {
                                    LogUtil.LogInfo("Unable to contact initial seed node {0}.  Re-Joining...", this._seedNode);
                                    Join(this._seedNode);
                                }

                                // otherwise, in the future, there will be a cache of seed nodes to check/join from...
                                // as it may be the case that the seed node simply has disconnected from the network.
                            }
                        }
                    }
                    else
                    {
                        // subsequent iterations will go through the core logic
                        this.m_HasReJoinRun = true;
                    }
                }
                catch (Exception e)
                {
                    LogUtil.LogError("Error occured during ReJoin ({0})", e);
                }

                // TODO: the delay between iterations, here, is configurable, and
                // ideally should be retrieved from configuration or otherwise passed in...
                Thread.Sleep(1000);
            }
        }
    }
}
